#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_console.h"
#include "argtable3/argtable3.h"
//#include "cmd_decl.h"
#include "nvs_flash.h"
#include "nvs.h"
#include "cmd_nvs.h"

/*
static void register_***();   命令注册声明
在命令组注册函数添加命令注册
命令参数结构体构造
命令处理函数
命令注册绑定函数

 */
//缓冲区默认大小
#define NVS_BUF_LEN 128

//static void register_test_nvs();
void register_nvs(){
	register_read_nvs();        //读取命令
	register_write_nvs();       //写入命令
	register_stats_nvs();       //状态命令
	register_del_nvs();         //删除命令
	
}

/******************************** 公共函数 *********************************/

const char * read_nvs_str(const char * name,const char * key, uint8_t * len){
	//初始化变量
	esp_err_t err;
	nvs_handle nvs_handle;
	//str获取参数
	uint8_t length;
	//默认 缓存128字节，最多127个字符+"/0"结束符
	char * buf = NULL;

	err=nvs_open( name != NULL?name:NVS_DEFAULT_PART_NAME, NVS_READONLY,&nvs_handle);
	if (err != ESP_OK) {
        printf("Error (%s) 打开NVS句柄!\n", esp_err_to_name(err));
		return -1;
    } 

	if(key != NULL ){
		buf = (char *)malloc(NVS_BUF_LEN);
		err=nvs_get_str(nvs_handle,key,buf,len);
		switch (err) {
			case ESP_OK:
				//printf("Done\n");
				//printf("%s = %s len:%d\n",key,out_value,length);
				break;
			case ESP_ERR_NVS_NOT_FOUND:
				printf("该值尚未初始化!\n");
				break;
			default :
				printf("读取错误 (%s) !\n", esp_err_to_name(err));
			}
	}

	//关闭nvs 句柄
	nvs_close(nvs_handle);
	return buf;
}

uint8_t write_nvs_str(const char * name,const char * key, const char * value){
	//初始化变量
	esp_err_t err;
	nvs_handle nvs_handle;


	err=nvs_open( name != NULL?name:NVS_DEFAULT_PART_NAME, NVS_READWRITE,&nvs_handle);
	if (err != ESP_OK) {
        printf("Error (%s) 打开NVS句柄!\n", esp_err_to_name(err));
		return -1;
    } 

	if(key != NULL && value != NULL){
		err = nvs_set_str(nvs_handle,key,value);
        //printf((err != ESP_OK) ? "失败!\n" : "完成\n");

		err = nvs_commit(nvs_handle);
        //printf((err != ESP_OK) ? "写nvs失败!\n" : "写nvs完成\n");
	}else{
		printf("key或value参数错误!\n");
		return 1;
	}

	//关闭nvs 句柄
	nvs_close(nvs_handle);
	return strlen(value);
}
/******************************** 公共函数 end *********************************/
static int read_nvs(int argc, char** argv){
	//初始化变量
	//str获取参数
	char * out_value;
	uint8_t length;

	//参数格式化
	int nerrors = arg_parse(argc, argv, (void**) &nvs_read_arg);
    if (nerrors != 0) {
        arg_print_errors(stderr, nvs_read_arg.end, argv[0]);
        return 1;
    }

	if(nvs_read_arg.str->count){
		
		out_value = read_nvs_str(nvs_read_arg.name->count?nvs_read_arg.name->sval[0]:NULL,nvs_read_arg.str->sval[0],&length);
		printf("%s = %s len:%d\n",nvs_read_arg.str->sval[0],out_value,length);
		//printf("out_value %s %p \n",out_value,out_value);
		free(out_value);
	}
	return 0;
}

static void register_read_nvs(){
	//参数表格式化
	nvs_read_arg.name = arg_str0("n", "name", "<str>", "名称空间.");
	nvs_read_arg.n32 = arg_str0("i", "int32", "<str>", "int key.");
	nvs_read_arg.str = arg_str0(NULL, NULL, "<str>", "str key.");
	nvs_read_arg.end = arg_end(2);
	//命令注册
	const esp_console_cmd_t cmd = {
        .command = "nvsr",
        .help = "nvs 读取指定name空间的key值",
        .hint = "[name] -s|i key",
        .func = &read_nvs,
        .argtable = &nvs_read_arg
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}

static int write_nvs(int argc, char** argv){
	//初始化变量

	//参数格式化
	int nerrors = arg_parse(argc, argv, (void**) &nvs_write_arg);
    if (nerrors != 0) {
        arg_print_errors(stderr, nvs_write_arg.end, argv[0]);
        return 1;
    }
/* 	//根据key空间来打开nvs
	const char * name = NVS_DEFAULT_PART_NAME;	//给参数定义默认值
	if(nvs_read_arg.name->count){
		name = nvs_read_arg.name->sval[0];
		}
	err=nvs_open( name, NVS_READWRITE ,&nvs_handle);
	if (err != ESP_OK) {
        	printf("Error (%s) 打开NVS手柄!\n", esp_err_to_name(err));
    	} 
		else {
        printf("%s 打开.\n",nvs_read_arg.name->sval[0]);
		}

	if(nvs_write_arg.key->count && (nvs_write_arg.ivalue->count || nvs_write_arg.svalue->count)){
		if(nvs_write_arg.ivalue->count){
			err = nvs_set_i32(nvs_handle,nvs_write_arg.key->sval[0],nvs_write_arg.ivalue->ival[0]);
        	printf((err != ESP_OK) ? "失败!\n" : "完成\n");
		}else if(nvs_write_arg.svalue->count){
			err = nvs_set_str(nvs_handle,nvs_write_arg.key->sval[0],nvs_write_arg.svalue->sval[0]);
        	printf((err != ESP_OK) ? "失败!\n" : "完成\n");
		}else{
			printf("没有该值!\n");
			return 1;
		}
		err = nvs_commit(nvs_handle);
        printf((err != ESP_OK) ? "写nvs失败!\n" : "写nvs完成\n");

	}else{
		printf("not key or value!\n");
		return 1;
	}


	//关闭nvs 句柄
	nvs_close(nvs_handle);
	printf("nvs close.\n"); 
*/

	if(nvs_write_arg.key->count && nvs_write_arg.svalue->count){
		uint8_t len = write_nvs_str(nvs_write_arg.name->count?nvs_write_arg.name->sval[0]:NULL,nvs_write_arg.key->sval[0],nvs_write_arg.svalue->sval[0]);
		printf("写入 name:%s %s:%s len:%d \n",nvs_write_arg.name->count?nvs_write_arg.name->sval[0]:NVS_DEFAULT_PART_NAME, \
										   nvs_write_arg.key->sval[0],nvs_write_arg.svalue->sval[0],len);
	}
	return 0;
}

static void register_write_nvs(){
	//参数表格式化
	nvs_write_arg.name = arg_str0("n", "name", "<str>", "key name.");
	nvs_write_arg.key =arg_str1(NULL, NULL, "<str>", "key.");
	nvs_write_arg.svalue =arg_str0("s", "str", "<str>", "str key.");
	nvs_write_arg.ivalue = arg_int0("i", "int32", "<n>", "int key.");
	nvs_write_arg.end = arg_end(2);
	//命令注册
	const esp_console_cmd_t cmd = {
        .command = "nvsw",
        .help = "nvs 写入 name key value",
        .hint = "[name] key -s|i value",
        .func = &write_nvs,
        .argtable = &nvs_write_arg
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}

static int stats_nvs(int argc, char** argv){
	nvs_stats_t stats;
	const char* nvs_np=NULL;
	//参数格式化
	int nerror = arg_parse(argc, argv, (void**) &nvs_st_arg);
    if (nerror != 0) {
       arg_print_errors(stderr, nvs_st_arg.end, argv[0]);
        return 1;
    }
	nvs_np=NVS_DEFAULT_PART_NAME;
	if(nvs_st_arg.name->count){
		nvs_np=nvs_st_arg.name->sval[0];
	}
	//nvs_np=nvs_st_arg.name->count?nvs_st_arg.name->sval[0]:NVS_DEFAULT_PART_NAME;
	printf("空间：%s ",nvs_np);
	if(nvs_get_stats(nvs_np, &stats) == ESP_OK){
		printf("使用:%d;空闲：%d;所有可用:%d;空间总数:%d\n",stats.used_entries,stats.free_entries,stats.total_entries,stats.namespace_count);
		if(nvs_st_arg.all->count){
			printf("-a 使用:%d;空闲：%d;所有可用:%d;空间总数:%d\n",stats.used_entries,stats.free_entries,stats.total_entries,stats.namespace_count);
		}
		return 0;	
	}else{
		printf("参数错误\n");
		return 1;
	}
}
static void register_stats_nvs(){
	//参数表格式化
	nvs_st_arg.name = arg_str0("n", "name", "<str>", "名称空间.");
    nvs_st_arg.all = arg_lit0("a","all", "全部信息.");
	nvs_st_arg.end = arg_end(2);
	//命令注册
	const esp_console_cmd_t cmd = {
        .command = "nvss",
        .help = "nvs 状态信息.",
        .hint = "name | all ",
        .func = &stats_nvs,
        .argtable = &nvs_st_arg
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}


static int del_nvs(int argc, char** argv){
	//初始化变量
	nvs_handle nvs_handle;
	nvs_stats_t stats;
	const char* nvs_np=NULL;

	//参数格式化
	int nerrors = arg_parse(argc, argv, (void**) &nvs_del_arg);
    if (nerrors != 0) {
        arg_print_errors(stderr, nvs_del_arg.end, argv[0]);
        return 1;
    }
	//(nvs_del_arg.name->count?nvs_del_arg.name->sval[0]:NULL)
	nvs_np=nvs_del_arg.name->count?nvs_del_arg.name->sval[0]:NVS_DEFAULT_PART_NAME;

	//all 参数执行
	if(nvs_del_arg.all->count){
			if(nvs_get_stats(nvs_np, &stats) == ESP_OK){
				if(stats.namespace_count != 0) {
					//nvs_flash 擦除
					nvs_flash_erase();
					//为默认的nvs_flash初始化
					nvs_flash_deinit();
					//初始化
					nvs_flash_init();
    			}
			}
			if(nvs_get_stats(nvs_np, &stats) == ESP_OK){
				printf("使用：%d;空闲：%d;所有可用：%d;空间数：%d\n",stats.used_entries,stats.free_entries,stats.total_entries,stats.namespace_count);
			}
			return 0;
	}

		//根据key空间来打开nvs
		if (nvs_open(nvs_np, NVS_READWRITE,&nvs_handle) != ESP_OK) {
        	printf("Error opening NVS handle!\n");
    	} else {
        printf("%s 打开成功.\n",nvs_np);
		}
	

	//根据键值删除key
	if(nvs_del_arg.key->count){
		if(nvs_erase_key(nvs_handle,nvs_del_arg.key->sval[0]) == ESP_OK){
			printf("删除key:%s 成功.\n",nvs_del_arg.key->sval[0]);
			nvs_close(nvs_handle);
			return 0;

		}
	}
	

	//清空空间key
		if(nvs_get_stats(nvs_np, &stats) == ESP_OK){
			if(stats.namespace_count != 0) {
				if(stats.used_entries != 0){
					if(nvs_erase_all(nvs_handle) == ESP_OK){
						if(nvs_get_stats(nvs_np, &stats) == ESP_OK){
							printf("空间：%s 使用：%d;空闲：%d;所有可用：%d;空间数：%d\n",nvs_np,stats.used_entries,stats.free_entries,stats.total_entries,stats.namespace_count);
						}
					}
				}
			}
		}

	


	//关闭nvs 句柄
	nvs_close(nvs_handle);
	//printf("nvs close.\n");
	return 0;
}

static void register_del_nvs(){
	//参数表格式化
	nvs_del_arg.name = arg_str0("n", "name", "<str>", "key name.");
	nvs_del_arg.key = arg_str0(NULL, "key", "<str>", "key.");
	nvs_del_arg.all = arg_lit0("a","all", "name all key.");
	nvs_del_arg.end = arg_end(3);
	//命令注册
	const esp_console_cmd_t cmd = {
        .command = "nvsd",
        .help = "nvs del name key all",
        .hint = "name | key | all",
        .func = &del_nvs,
        .argtable = &nvs_del_arg
    };
    ESP_ERROR_CHECK( esp_console_cmd_register(&cmd) );
}
